﻿//Copyright 2011 - Jonathan Allen

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Collections.Specialized;
using System.Globalization;
using System.ComponentModel;
using Granite.Eventing;
using System.Collections;

namespace Granite.Collections
{
	///// <summary>
	///// This creates a collection that represents a filtered view into another collection
	///// </summary>
	///// <typeparam name="T">Type of item in collection</typeparam>
	//public class FilteredCollection<T> : ICollection<T>, INotifyCollectionChanged where T : INotifyPropertyChanged
	//{
	//	readonly Predicate<T> m_FilterCriteria;
	//	readonly ObservableCollection<T> m_Source;
	//	readonly List<ItemStatus> m_KnownItems = new List<ItemStatus>();
	//	readonly ObservableCollection<T> m_VisibleItems = new ObservableCollection<T>();
	//	readonly CollectionChangedListener m_SourceCollectionChanged;
	//	readonly PropertyChangedListener m_ItemPropertyChanged;

	//	/// <summary>
	//	/// This creates a collection that represents a filtered view into another collection
	//	/// </summary>
	//	/// <param name="source">Source collection to observe</param>
	//	/// <param name="filterCriteria">Only items that evaluate as true will appear in the collection</param>
	//	public FilteredCollection(ObservableCollection<T> source, Predicate<T> filterCriteria)
	//	{
	//		m_FilterCriteria = filterCriteria;
	//		m_Source = source;
	//		m_SourceCollectionChanged = new CollectionChangedListener(SourceCollectionChanged);
	//		m_ItemPropertyChanged = new PropertyChangedListener(OnItemPropertyChanged);
 //           WeakEventHandler.AddHandler(m_Source, m_SourceCollectionChanged);

	//		m_VisibleItems.CollectionChanged += (s, e) => OnCollectionChanged(e);
	//	}

	//	void SourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
	//	{

	//		switch (e.Action)
	//		{
	//			case NotifyCollectionChangedAction.Add:

 //                   var newList = (from i in e.NewItems.Cast<T>() select new ItemStatus(i, m_FilterCriteria(i))).ToList();
	//				foreach (var entry in newList)
	//				{
	//					if (entry.Item is INotifyPropertyChangedWeak)
	//						((INotifyPropertyChangedWeak)entry.Item).AddHandler(m_ItemPropertyChanged);
	//					else
	//						entry.Item.PropertyChanged += OnItemPropertyChanged;
	//				}
	//				m_KnownItems.InsertRange(e.NewStartingIndex, newList);

	//				break;

	//			case NotifyCollectionChangedAction.Remove:

	//				foreach (var entry in m_KnownItems.SelectRange(e.OldStartingIndex, e.OldItems.Count))
	//				{
	//					if (entry.Item is INotifyPropertyChangedWeak)
	//						((INotifyPropertyChangedWeak)entry.Item).RemoveHandler(m_ItemPropertyChanged);
	//					else
	//						entry.Item.PropertyChanged -= OnItemPropertyChanged;
	//				}
	//				m_KnownItems.RemoveRange(e.OldStartingIndex, e.OldItems.Count);

	//				break;

	//			case NotifyCollectionChangedAction.Reset:

	//				foreach (var entry in m_KnownItems)
	//				{
	//					if (entry.Item is INotifyPropertyChangedWeak)
	//						((INotifyPropertyChangedWeak)entry.Item).RemoveHandler(m_ItemPropertyChanged);
	//					else
	//						entry.Item.PropertyChanged -= OnItemPropertyChanged;
	//				}
	//				m_KnownItems.Clear();

	//				foreach (var item in m_Source)
	//					m_KnownItems.Add(new ItemStatus(item, m_FilterCriteria(item)));

	//				break;

	//			case NotifyCollectionChangedAction.Replace:

 //                   var newList2 = (from i in e.NewItems.Cast<T>() select new ItemStatus(i, m_FilterCriteria(i))).ToList();
	//				for (var i = 0; i < newList2.Count; i++)
	//				{
	//					var entry = m_KnownItems[e.NewStartingIndex + i];
	//					if (entry.Item is INotifyPropertyChangedWeak)
	//						((INotifyPropertyChangedWeak)entry.Item).RemoveHandler(m_ItemPropertyChanged);
	//					else
	//						entry.Item.PropertyChanged -= OnItemPropertyChanged;

 //                       if (newList2[i].Item is INotifyPropertyChangedWeak)
 //                           ((INotifyPropertyChangedWeak)newList2[i].Item).RemoveHandler(m_ItemPropertyChanged);
 //                       else
 //                           newList2[i].Item.PropertyChanged -= OnItemPropertyChanged;

	//					m_KnownItems[e.NewStartingIndex + i] = newList2[i];
	//				}

	//				break;

	//			default:
	//				//TODO - Handle the other cases for e.Action
	//				throw new NotImplementedException(string.Format(CultureInfo.InvariantCulture, "Action type {0} is not supported.", e.Action));
	//		}

	//		UpdateVisibleList();

	//	}

	//	void UpdateVisibleList()
	//	{
	//		var targetIndex = 0;
	//		for (var sourceIndex = 0; sourceIndex < m_KnownItems.Count; sourceIndex++)
	//		{
	//			if (m_KnownItems[sourceIndex].IsVisible)
	//			{
	//				if (m_VisibleItems.Count == targetIndex) //add to the end
	//				{
	//					m_VisibleItems.Add(m_KnownItems[sourceIndex].Item);
	//				}
	//				else if (!Object.Equals(m_KnownItems[sourceIndex].Item, m_VisibleItems[sourceIndex])) //replace, bubbling down as it goes
	//				{
	//					m_VisibleItems[sourceIndex] = m_KnownItems[sourceIndex].Item;
	//				}
	//				targetIndex++;
	//			}
	//		}

	//		//remove any extra items
	//		while (m_VisibleItems.Count > targetIndex)
	//			m_VisibleItems.RemoveAt(m_VisibleItems.Count - 1);

	//	}

	//	void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
	//	{
	//		var visibleChanged = false;
	//		foreach (var item in m_KnownItems)
	//		{
	//			if (Object.Equals(item.Item, sender))
	//			{
	//				var newVisible = m_FilterCriteria(item.Item);
	//				if (newVisible != item.IsVisible)
	//				{
	//					visibleChanged = true;
	//					item.IsVisible = newVisible;
	//				}
	//			}
	//		}
	//		if (visibleChanged)
	//			UpdateVisibleList();
	//	}

	//	class ItemStatus
	//	{
	//		readonly T m_Item;
	//		public ItemStatus(T item, bool isVisible)
	//		{
	//			m_Item = item;
	//			IsVisible = isVisible;
	//		}

	//		public bool IsVisible { get; set; }

	//		public T Item
	//		{
	//			get { return m_Item; }
	//		}

	//	}

	//	/// <summary>
	//	/// Occurs when the collection changes.
	//	/// </summary>
 //       public event NotifyCollectionChangedEventHandler CollectionChanged;


	//	/// <summary>
	//	/// Triggers the CollectionChanged event.
	//	/// </summary>
	//	void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
	//	{
	//		if (CollectionChanged != null)
	//			CollectionChanged(this, e);
	//	}


	//	void ICollection<T>.Add(T item)
	//	{
	//		throw new InvalidOperationException("Collection is read-only");			
	//	}

	//	void ICollection<T>.Clear()
	//	{
	//		throw new InvalidOperationException("Collection is read-only");
	//	}

	//	/// <summary>
	//	/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1" /> contains a specific value.
	//	/// </summary>
	//	/// <returns>
	//	/// true if <paramref name="item" /> is found in the <see cref="T:System.Collections.Generic.ICollection`1" />; otherwise, false.
	//	/// </returns>
	//	/// <param name="item">
	//	/// The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1" />.
	//	/// </param>
 //       public bool Contains(T item)
	//	{
	//		return m_VisibleItems.Contains(item);
	//	}

	//	/// <summary>
	//	/// 
	//	/// </summary>
	//	/// <param name="array"></param>
	//	/// <param name="arrayIndex"></param>
 //       public void CopyTo(T[] array, int arrayIndex)
	//	{
	//		m_VisibleItems.CopyTo(array, arrayIndex);
	//	}

	//	/// <summary>
	//	/// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.
	//	/// </summary>
	//	/// <returns>
	//	/// The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.
	//	/// </returns>
 //       public int Count
	//	{
	//		get { return m_VisibleItems.Count; }
	//	}

	//	/// <summary>
	//	/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.
	//	/// </summary>
	//	/// <returns>
	//	/// true if the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only; otherwise, false.
	//	/// </returns>
 //       public bool IsReadOnly
	//	{
	//		get { return true; }
	//	}

	//	bool ICollection<T>.Remove(T item)
	//	{
	//		throw new InvalidOperationException("Collection is read-only");
	//	}

	//	/// <summary>
	//	/// Returns an enumerator that iterates through the collection.
	//	/// </summary>
	//	/// <returns>
	//	/// A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.
	//	/// </returns>
	//	/// <filterpriority>1</filterpriority>
 //       public IEnumerator<T> GetEnumerator()
	//	{
	//		return m_VisibleItems.GetEnumerator();
	//	}

	//	IEnumerator IEnumerable.GetEnumerator()
	//	{
	//		return m_VisibleItems.GetEnumerator();
	//	}
	//}
}
